#include <iostream>
#include <string>
#include <fstream>
#include <fmt/format.h>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
#include <vector>
using namespace std;

class Record
{
    template <typename Archive>
    friend void serialize(Archive &archive, Record &record);

public:
    explicit Record(int account = 0, std::string_view first = "", std::string_view last = "", double balance = 0.0)
        : m_account(account), m_first(first), m_last(last), m_balance(balance)
    {
    }

    int getAccount() const { return m_account; }
    const std::string &getFirst() const { return m_first; }
    const std::string &getLast() const { return m_last; }
    double getBlance() const { return m_balance; }

private:
    int m_account{};
    std::string m_first{};
    std::string m_last{};
    double m_balance{};
};

template <typename Archive>
void serialize(Archive &archive, Record &record)
{
    archive(cereal::make_nvp("account", record.m_account),  //
            cereal::make_nvp("first", record.m_first),      //
            cereal::make_nvp("last", record.m_last),        //
            cereal::make_nvp("balance", record.m_balance));
}

void dispalyRecords(const std::vector<Record> &records)
{
    for (const auto &r : records)
    {
        std::cout << fmt::format("{} {} {} {:.2f}\n", r.getAccount(), r.getFirst(), r.getLast(), r.getBlance());
    }
}

int main()
{
    std::vector<Record> records{
        Record{ 100, "Brian", "Blue", 123.45 },
        Record{ 200, "Sue", "Green", 987.5 },
    };
    std::cout << "Records to serialize:\n";
    dispalyRecords(records);

    if (std::ofstream output{ "records.json" })
    {
        cereal::JSONOutputArchive archive{ output };
        archive(cereal::make_nvp("records", records));
    }

    //read from json
    if (std::ifstream input{ "records.json" })
    {
        cereal::JSONInputArchive archive{ input };
        std::vector<Record> records{};
        archive(records);
        std::cout << "\nDeserialized records:\n";
        dispalyRecords(records);
    }
    return 0;
}
